#ifndef __OSAMCC18_H__
#define __OSAMCC18_H__


#ifndef OS_SMSG_SIZE
#define OS_SMSG_SIZE    0   // We can not use sizeof() because it does not work with #ifdef directive
#endif

/*************************************************************************************************************************/
//------------------------------------------------------------------------------
//    FSR = FSR0


extern          near unsigned char      TOSL;
extern          near unsigned char      TOSH;
extern          near unsigned char      TOSU;
extern volatile near unsigned char      STKPTR;
extern volatile near unsigned char      INTCON;
extern volatile near unsigned char      RCON;


#define _fsr        FSR0
#define _indf       INDF0
#define _postinc    POSTINC0
#define _postdec    POSTDEC0
#define _preinc     PREINC0


#define _postinc1   POSTINC1
#define _postdec1   POSTDEC1
#define _indf1      INDF1
#define _fsr1l      FSR1L
#define _fsr2l      FSR2L

#define _pcl        PCL
#define _pclath     PCLATH
#define _pclatu     PCLATU
#define _status     STATUS
#define _tosh       TOSH
#define _tosl       TOSL
#define _tosu       TOSU
#define _bsr        BSR
#define _wreg       WREG
#define _stkptr     STKPTR
#define _intcon     INTCON
#define _rcon       RCON


#define _FSR_TYPE            unsigned int
#define _PIC18_ERRATA_NOP()  _asm nop _endasm
#define _PIC18_POP()         _asm pop _endasm

#define _SET_TASK_IRP()      // Empty macro (used only for PIC16)



// Code pointer (used in OST_TCB)

#if defined(__SMALL__)
    #define OST_CODE_POINTER    unsigned int    
    #define OS_CODE_POINTER_SIZE    2
#else
    #define OST_CODE_POINTER    unsigned long
    #define OS_CODE_POINTER_SIZE    4
#endif


#define OST_TASK_POINTER   OS_TASKS_BANK OST_TCB *



#define OS_CLRWDT()   _asm clrwdt   _endasm
#define OS_ClrWdt()   _asm clrwdt   _endasm
#define OS_SLEEP()    _asm sleep    _endasm


//______________________________________________________________________________
/******************************************************************************
 * Switch control routines:
 *
 *  _OS_JumpToTask() - jump indirectly from kernel (OS_Sched) into task
 *  _OS_SaveRetAddr() - task return to this point 
 *
 *  _OS_GetReturnPoint() - exit from task and save context
 *  _OS_CallGetReturnPoint() - save context without exiting task
 *  _OS_ReturnNoSave() - exit task without saving context
 *
 *******************************************************************************/


#if defined(__SMALL__)
    #define _OS_SetPC()             \
        _pclath = _postdec;         \
        _asm                        \
            movf    _postdec, 0, 0  \
            movwf   _pcl, 0         \
        _endasm

    
    #define _OS_SavePC()            \
        _postdec = _tosh;           \
        _postdec = _tosl;

#else
    #define _OS_SetPC()             \
        _postdec = 0;               \
        _pclatu = _postdec;         \
        _pclath = _postdec;         \
        _asm                        \
            movf    _postdec, 0, 0  \
            movwf   _pcl, 0         \
        _endasm

    #define _OS_SavePC()            \
        _postdec = 0;               \
        _postdec = _tosu;           \
        _postdec = _tosh;           \
        _postdec = _tosl;

#endif


    #define _OS_JumpToTask()                                                    \
        {                                                                       \
            _OS_SET_FSR_CUR_TASK_W(OS_CODE_POINTER_SIZE+1);                     \
            _asm                                                                \
                bra     _OS_call_indirrect                                      \
        _OS_jump_indirrect:                                                     \
            _endasm                                                             \
            if (_indf) {                                                        \
                _indf1 = _fsr2l;                                                \
                _fsr2l = _fsr1l + 1;                                            \
            }                                                                   \
            _OS_tempH = _fsr1l;                                                 \
            _fsr1l += _postdec;                                                 \
            _OS_SetPC();                                                        \
            /* Now FSR points to OS_CurTask->State    */                        \
            _asm                                                                \
        _OS_call_indirrect:                                                     \
                rcall   _OS_jump_indirrect                                      \
            _endasm                                                             \
            if (_fsr1l != _OS_tempH) {                                          \
                _fsr1l = _OS_tempH;                                             \
                _fsr2l = _indf1;                                                \
            }                                                                   \
        }

    #define _OS_SaveRetAddr()

    #define _OS_if_Ready()  _OS_SET_FSR_CUR_TASK();                             \
                            if (_OS_bTaskReady)   


  


 
//------------------------------------------------------------------------------
extern void OS_SchedRetPoint (void);
extern void OS_SchedRetPointNoSave (void);
extern void OS_ClearReady (void);
extern void OS_ClearReadySetCanContinue (void);

extern void  __OS_SET_FSR_CUR_TASK_W (void);
extern void  _OS_SET_FSR_CUR_TASK (void);

#define _OS_SET_FSR_CUR_TASK_W(w)               \
    {   _wreg = w;                              \
        __OS_SET_FSR_CUR_TASK_W();              \
    }


//------------------------------------------------------------------------------
#define _OS_GetReturnPoint()                    \
    {                                           \
        OS_SchedRetPoint();                     \
        _PIC18_ERRATA_NOP();                    \
    }
    
//------------------------------------------------------------------------------
#define _OS_CLEAR_READY()                       \
    {                                           \
        OS_ClearReady();                        \
        _PIC18_ERRATA_NOP();                    \
    }
//------------------------------------------------------------------------------
#define _OS_CLEAR_READY_SET_CANCONTINUE()       \
    {                                           \
        OS_ClearReadySetCanContinue();          \
        _PIC18_ERRATA_NOP();                    \
    }
//------------------------------------------------------------------------------
#define _OS_ReturnNoSave()                      \
    {                                           \
        OS_SchedRetPointNoSave();               \
        _PIC18_ERRATA_NOP();                    \
    }                                           \
//------------------------------------------------------------------------------
    

 



















/******************************************************************************************
 *
 *  WORK WITH DYNAMIC TIMERS
 *
 ******************************************************************************************/

#ifdef OS_ENABLE_DTIMERS


#if   OS_DTIMER_SIZE == 1
    #define OS_INC_DTIMER()                                                             \
        {                                                                               \
            _asm                                                                        \
                movlw   3                                                               \
                addwf   _fsr, 1, 0                                                      \
                incf    _postdec, 1, 0  /* FSR0L can't overflow here */                 \
                movf    _postdec, 0, 0                                                  \
                movf    _postdec, 0, 0                                                  \
            _endasm                                                                     \
            if (_status & 0x01) _OS_SetIndfTimerTimeout;                                \
        }

        
#elif OS_DTIMER_SIZE == 2
    #define OS_INC_DTIMER()                                                             \
        {                                                                               \
            _OS_DTimers.Flags.bTimeout = 0;                                             \
            _asm                                                                        \
                movlw   3                                                               \
                addwf   _fsr, 1, 0                                                      \
                movlw   0                                                               \
                incf    _postinc, 1, 0                                                  \
                addwfc  _postdec, 1, 0                                                  \
            _endasm                                                                     \
            if (_status & 0x01) _OS_DTimers.Flags.bTimeout = 1;                         \
            _asm                                                                        \
                movlw   3                                                               \
                subwf   _fsr, 1, 0                                                      \
            _endasm                                                                     \
            if (_OS_DTimers.Flags.bTimeout)                                             \
                _OS_SetIndfTimerTimeout;                                                \
        }


#elif OS_DTIMER_SIZE == 4
    #define OS_INC_DTIMER()                                                             \
        {                                                                               \
            _OS_DTimers.Flags.bTimeout = 0;                                             \
            _asm                                                                        \
                movlw   3                                                               \
                addwf   _fsr, 1, 0                                                      \
                movlw   0                                                               \
                incf    _postinc, 1, 0                                                  \
                addwfc  _postinc, 1, 0                                                  \
                addwfc  _postinc, 1, 0                                                  \
                addwfc  _postdec, 1, 0                                                  \
            _endasm                                                                     \
            if (_status & 0x01) _OS_DTimers.Flags.bTimeout = 1;                         \
            _asm                                                                        \
                movlw   5                                                               \
                subwf   _fsr, 1, 0                                                      \
            _endasm                                                                     \
            if (_OS_DTimers.Flags.bTimeout)                                             \
                _OS_SetIndfTimerTimeout;                                                \
        }

#endif


#define __OS_DTimersWork()                              \
    {                                                   \
        _fsr = (_FSR_TYPE) &_OS_DTimers.Flags;          \
    REPEAT:                                             \
        if (_OS_CheckPostincTimerNextEnable)            \
        {                                               \
            /* Point FSR to next timer           */     \
            _asm                                        \
                movf    _postinc, 0, 0                  \
                movff   _postdec, _fsr + 1              \
                movwf   _fsr + 0, 0                     \
            _endasm                                     \
            if (!_OS_CheckIndfTimerRun) goto REPEAT;    \
            OS_INC_DTIMER();                            \
            goto REPEAT;                                \
        }                                               \
    }



#endif  // OS_ENABLE_DTIMER

/******************************************************************************************
 *
 *
 *
 ******************************************************************************************/





#endif
